<?php

declare(strict_types=1);

namespace sws\event;

use Closure;
use Swoole\Http\Request;
use Swoole\Http\Response;
use sws\Config;
use sws\Container;
use sws\Event;
use sws\exception\RouteNotFoundException;
use sws\route\Route;
use sws\Server;

class FrameEvent
{

    /**
     * 获取实例
     * @return FrameEvent
     */
    public static function getInstance(): FrameEvent
    {
        return Container::getInstance()->make(FrameEvent::class);
    }

    /**
     * 监听框架事件
     */
    public function listenEvent()
    {
        $methods = get_class_methods($this);
        foreach ($methods as $method) {
            if ($method == 'listenEvent') {
                continue;
            }
            $this->$method();
        }
    }

    /**
     * onRequest事件监听
     */
    protected function onRequest()
    {
        Event::getInstance()->listen('onRequest', function (Request $request, Response $response) {

            $res = Container::getInstance()->make(Route::class)->match($request->server['request_method'], $request->server['request_uri']);

            if (null === $res) {
                throw new RouteNotFoundException(404, 'Route Not Found');
            }
            list($isDynamic, $list) = $res;

            //分发路由，执行中间件调用
            $serverName = Server::getInstance()->getName();
            //获取全局中间件
            $middlewares = Config::getInstance()->get('middleware.' . $serverName, []);
            $middlewares = array_merge($middlewares, $list['middleware'] ?? []);
            array_push($middlewares, $list['handle']);
            $middlewares = array_reverse($middlewares);
            //获取请求对象,注入中间件闭包
            $request = Container::getInstance()->get('request');
            $next = null;
            //构建嵌套闭包
            foreach ($middlewares as $middleware) {
                //把请求对象当做参数传给闭包
                $next = function ($request) use ($next, $middleware, $list, $isDynamic) {
                    //如果执行到了目标路由
                    if ($middleware == $list['handle']) {

                        //如果是动态路由，构建方法参数
                        $variable = [];
                        if (true === $isDynamic) {
                            foreach ($list['variable'] as $k => $value) {
                                $variable[$value] = $list['matches'][$k + 1];
                            }
                        }
                        return Container::getInstance()->invoke($middleware, $variable);
                    }

                    if ($middleware instanceof Closure) {
                        return Container::getInstance()->invoke($middleware, [$request, $next]);
                    } else {
                        return Container::getInstance()->invoke([$middleware, 'handle'], [$request, $next]);
                    }
                };
            }
            $responseData = $next($request);

            //如果链接对象未结束,发送消息
            if (true === $response->isWritable()) {
                //如果返回了数组或者字符串向客户端发送响应结果
                if (is_array($responseData)) {
                    $responseData = json_encode($responseData);
                }
                $response->end((string)$responseData);
            }

        });
    }

}
